-
Notifications
You must be signed in to change notification settings - Fork 78
SLVS-2465 Add analysis engine to connect with Roslyn APIs #6368
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
SLVS-2465 Add analysis engine to connect with Roslyn APIs #6368
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please rename all classes to not contain Sonar
. The product name makes the class names longer and it does not bring any clarity on their responsibility.
Consider grouping the files inside the Analysis
folder into different sub-folders. For now it's very difficult to find the classes.
I also have some additional feedback.
src/RoslynAnalyzerServer/Analysis/Wrappers/SonarRoslynProjectWrapper.cs
Outdated
Show resolved
Hide resolved
src/RoslynAnalyzerServer/Analysis/DiagnosticDuplicatesComparer.cs
Outdated
Show resolved
Hide resolved
src/RoslynAnalyzerServer.UnitTests/Analysis/DiagnosticDuplicatesComparerTests.cs
Show resolved
Hide resolved
src/RoslynAnalyzerServer.UnitTests/Analysis/SequentialSonarRoslynAnalysisEngineTests.cs
Outdated
Show resolved
Hide resolved
src/RoslynAnalyzerServer.UnitTests/Analysis/SequentialSonarRoslynAnalysisEngineTests.cs
Outdated
Show resolved
Hide resolved
src/RoslynAnalyzerServer/Analysis/SonarRoslynProjectAnalysisSet.cs
Outdated
Show resolved
Hide resolved
|
||
foreach (var filePath in filePaths) | ||
{ | ||
if (!project.ContainsDocument(filePath, out var analysisFilePath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For each project we are iterating multiple times through the files (inside SonarRoslynProjectWrapper.ContainsDocument
), which can have a real hit on performance. Instead we should cache the list of file names and the filtering applied to them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there another way of doing this? I can see the analysisFilePath
seems to always be the same as the filePath
, except for Razor files. When I open the files in our solution and add TODO comments, the analysis is pretty slow. I can't be sure this is the main issue, but it could be.
We also have another task to not allow a request to be executed for a file that is not in the current solution.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The analysis is 'slow' because 1) it waits for semantic analysis to finish before publishing 2) there's a 500ms delay before triggering the analysis
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the point of this other task? If the file is not part of the solution it will not be found here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the point of this other task?
Security. We should not accept requests for files that are not part of the solution. Also we have to prevent directory traversal attacks
The analysis is 'slow' because 1) it waits for semantic analysis to finish before publishing 2) there's a 500ms delay before triggering the analysis
But traversing all the files for all the projects is also a slow operation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would it be rejected, based on what? How do you know if a file is part of the solution without looking into the solution?
We will be looking at the solution, of course. And that's the point. That the commands provider would not even be called if the request is for a file that is not part of the solution. My concern is regarding performance. I can update the other task, I guess to remove this check here and think about improving performance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only other way to see if the file belongs to the solution is to look at the DTE/IVsHierarchy, and I think that would require us to switch to UI thread, which is worse than the linear search here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current linear search is searching for x
amount of files that have to be analyzed in the y
amount of projects.
Anyway the file paths have to be validated at the beginning of the request. I updated the other task and it should be a separate PR
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But what's the alternative here? Doing the same but on UI thread?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure which approach will be taken. It will be defined in the task.
Could be either using IVsHierarchy
, either the VsWorkspace
with some improvements (e.g. parallelizing the search on different threads).
src/RoslynAnalyzerServer/Analysis/Wrappers/SonarRoslynWorkspaceWrapper.cs
Outdated
Show resolved
Hide resolved
@@ -33,6 +33,8 @@ namespace SonarLint.VisualStudio.RoslynAnalyzerServer.Analysis; | |||
[method: ImportingConstructor] | |||
internal class SonarRoslynProjectCompilationProvider(ILogger logger) : ISonarRoslynProjectCompilationProvider | |||
{ | |||
private readonly ILogger logger = logger.ForContext("Roslyn Analysis", "Analyzer Exception"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logger context seems like it's belonging to the class. But the Analyzer Exception
context should only be used by OnAnalyzerException
. I would split the two contexts: "Roslyn Analysis" for the field logger and move "Analyzer Exception" inside the method
|
||
return analysisFilePath != null; | ||
} | ||
|
||
private bool IsCodeBehindRazor(string razorFilePath, string candidateDocumentPath) => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe the name should be IsGeneratedRazorClass
and the comment should be moved as the method doc?
[TestMethod] | ||
public void GetHashCode_SameObjects_ReturnsSameHashCode() | ||
{ | ||
var diagnostic2 = CreateDiagnostic("rule1", "file1.cs", 1, 1, 1, 10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not why I suggested this change. Is for clean code purposes: if you want to update any of the diagnostic1
field, no adaption would be needed to this class. With the currently hard-coded values, you would have to adapt lots of tests.
My proposal does not change that the assertion happens by value.
|
||
namespace SonarLint.VisualStudio.RoslynAnalyzerServer.Analysis; | ||
|
||
public class SonarDiagnostic( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not about implementing the model according to the wrong contract. It's about implementing the model differently and then we have more work in the plugin side as well.
For example, the Diagnostic
has the primary location information on its level. Instead you created another property called PrimaryLocation
, which contains that info. We could have spared us some work if you would have looked at the model and made it consistent.
|
||
foreach (var filePath in filePaths) | ||
{ | ||
if (!project.ContainsDocument(filePath, out var analysisFilePath)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How would it be rejected, based on what? How do you know if a file is part of the solution without looking into the solution?
We will be looking at the solution, of course. And that's the point. That the commands provider would not even be called if the request is for a file that is not part of the solution. My concern is regarding performance. I can update the other task, I guess to remove this check here and think about improving performance.
2ee49fd
to
45f4257
Compare
6a0ce78
into
feature/sqvs-roslyn-plugin
🤖 Pull Request summaryRefactors SonarCompositeRuleId.GetFullErrorCode method and adds comprehensive Roslyn analysis engine • Extracted GetFullErrorCode as public static method in SonarCompositeRuleId class with unit tests Key areas to focus review on:
|
[SLVS-2465](https://sonarsource.atlassian.net/browse/SLVS-2465) Part of <!-- Only for standalone PRs without Jira issue in the PR title: * Replace this comment with Epic ID to create a new Task in Jira * Replace this comment with Issue ID to create a new Sub-Task in Jira * Ignore or delete this note to create a new Task in Jira without a parent --> [SLVS-2465]: https://sonarsource.atlassian.net/browse/SLVS-2465?atlOrigin=eyJpIjoiNWRkNTljNzYxNjVmNDY3MDlhMDU5Y2ZhYzA5YTRkZjUiLCJwIjoiZ2l0aHViLWNvbS1KU1cifQ
SLVS-2465
Part of